CloudFormationでAWS WAFのログをCloudWatchLogsに出力してみた
こんにちは!AWS事業本部のおつまみです。
みなさん!AWS WAFのWebACLトラフィックログは有効化していますか?
2023年5月時点でログは以下のサービスに出力することができるようになっています。
- CloudWatch Logs
- S3
- Kinesis
2021年11月より、CloudWatch Logs、S3に直接がログが出力できるようになっています。
詳細はこちらのブログをご確認ください。
今回はCloudFormationを利用し、AWS WAFのログをCloudWatchLogsに出力する環境を構築してみたいと思います。
ハマった箇所もあったので、その点についても合わせてご紹介します。
S3に出力する環境方法を知りたい方はこちらのブログをご確認ください。
構成図
本記事で構築するAWS環境は以下の構成です。
背景が赤色の範囲が本記事で構築するリソースです。
- AWS WAF(WebAcl)
- CloudWatch Logs log group
背景が灰色の範囲は、既存環境のリソースです。
※作成方法は割愛します。
- ALB
- EC2
やってみた
実行するCloudFormationテンプレート
AWSTemplateFormatVersion: '2010-09-09' Description: "create waf Resources" # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: PJPrefix: Type: String Default: "demo" Description: "Fill in the name of the system name." Env: Type: String Default: "test" Description: "Fill in the name of the environment." WebAclAssociationResourceArn: Type: String Default: "arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX" Description: Enter RegionalResource(ALB,APIGateway,AppSync) ARN or CloudFront ARN to associate with WEBACL. # ------------------------------------------------------------# # create Resources # ------------------------------------------------------------# Resources: WebACL: Type: "AWS::WAFv2::WebACL" Properties: Name: !Sub ${PJPrefix}-${Env}-alb-acl Scope: "REGIONAL" DefaultAction: Allow: {} Description: "Web ACL for InternetALB" VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl Rules: - Name: "AWS-AWSManagedRulesCommonRuleSet" Priority: 1 OverrideAction: None: {} VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: "AWS-AWSManagedRulesCommonRuleSet" Statement: ManagedRuleGroupStatement: Name: "AWSManagedRulesCommonRuleSet" VendorName: "AWS" WAFLogConfig: Type: AWS::WAFv2::LoggingConfiguration Properties: LogDestinationConfigs: !GetAtt WAFLogGroup.Arn ResourceArn: !GetAtt WebACL.Arn WebACLAssociation: Type: AWS::WAFv2::WebACLAssociation Properties: ResourceArn: !Ref WebAclAssociationResourceArn WebACLArn: !GetAtt WebACL.Arn WAFLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl RetentionInDays: 365 Tags: - Key: Name Value: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl WAFToCWLogsPolicy: Type: AWS::Logs::ResourcePolicy Properties: PolicyName: WAFToCWLogsPolicy PolicyDocument: Fn::Sub: - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "${CloudWatchLogsLogGroupArn}", "Condition": { "StringEquals": { "aws:SourceAccount": ${AWS::AccountId} }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*" } } } ] } - CloudWatchLogsLogGroupArn: !GetAtt WAFLogGroup.Arn
今回テンプレート内で作成するリソースは以下です。
- AWS WAF
- WebACL
- LoggingConfiguration(ログ出力先の設定)
- WebACLAssociation(Web Aclに関連付けするリソースの設定)
- CloudWatchLogs
- LogGroup
- ResourcePolicy
各リソースについて、簡単に解説します。
AWS WAF
WebAcl
WAFはWeb Aclという単位でリソースの作成、設定を行います。
ルールは今回AWS提供のマネージドルールAWS-AWSManagedRulesCommonRuleSet
を設定しました。要件に応じて変更してください。
WebACL: Type: "AWS::WAFv2::WebACL" Properties: Name: !Sub ${PJPrefix}-${Env}-alb-acl Scope: "REGIONAL" DefaultAction: Allow: {} Description: "Web ACL for InternetALB" VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl Rules: - Name: "AWS-AWSManagedRulesCommonRuleSet" Priority: 1 OverrideAction: None: {} VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: "AWS-AWSManagedRulesCommonRuleSet" Statement: ManagedRuleGroupStatement: Name: "AWSManagedRulesCommonRuleSet" VendorName: "AWS"
CloudFormationの記述方法は下記を参考にしています。
AWS::WAFv2::WebACL - AWS CloudFormation
AWS::WAFv2::WebACL Rule - AWS CloudFormation
LoggingConfiguration
WAFのWebACLトラフィックログ出力先の設定を行います。
WAFLogConfig: Type: AWS::WAFv2::LoggingConfiguration Properties: LogDestinationConfigs: !GetAtt WAFLogGroup.Arn ResourceArn: !GetAtt WebACL.Arn
CloudFormatinonの記述方法は下記を参考にしています。
AWS::WAFv2::LoggingConfiguration - AWS CloudFormation
WebACLAssociation
Web Aclに関連付けするリソースの設定を行います。
今回は既に構築済のALBのARNをParameterで指定し、ResourceArn
で関連付けています。
WebACLAssociation: Type: AWS::WAFv2::WebACLAssociation Properties: ResourceArn: !Ref WebAclAssociationResourceArn WebACLArn: !GetAtt WebACL.Arn
CloudFormatinonの記述方法は下記を参考にしています。
AWS::WAFv2::WebACLAssociation - AWS CloudFormation
CloudWatchLogs
LogGroup
WebACLトラフィックログ出力先となるCloudWatchLogs Loggroupを作成します。RetentionInDays
で保持期間を設定しています。 今回は365(1年)
で設定していますが、コストに関係する部分であるため、必要に応じて設定してください。
WAFLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl RetentionInDays: 365 Tags: - Key: Name Value: !Sub aws-waf-logs-${PJPrefix}-${Env}-alb-acl
CloudFormatinonの記述方法は下記を参考にしています。
AWS::Logs::LogGroup - AWS CloudFormation
ResourcePolicy
WAFのWebACLトラフィックログを出力するために、CloudWatchLogsに与えるリソースベースポリシーの作成を行います。
当初はこのポリシーを作成しておらず、ハマりしました。。
詳細は後半で解説します。
WAFToCWLogsPolicy: Type: AWS::Logs::ResourcePolicy Properties: PolicyName: WAFToCWLogsPolicy PolicyDocument: Fn::Sub: - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "${CloudWatchLogsLogGroupArn}", "Condition": { "StringEquals": { "aws:SourceAccount": ${AWS::AccountId} }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*" } } } ] } - CloudWatchLogsLogGroupArn: !GetAtt WAFLogGroup.Arn
CloudFormatinonの記述方法は下記を参考にしています。
AWS::Logs::ResourcePolicy - AWS CloudFormation
CloudFormation実行
今回はマネジメントコンソール経由でCloudFormationテンプレートを実行します。
リージョンは関連づけるリソースがある東京リージョン
を指定し、テンプレートをアップロードします。
パラメータは以下のように設定します。
値 | 説明 |
---|---|
スタックの名前 | 任意の名前 |
Env | AWSリソースの接頭語として付与できる文字列(環境名)を設定します。 |
Prefix | AWSリソースの接頭語として付与できる文字列(プロジェクト名など)を設定します。 |
WebAclAssociationResourceArn | WebAclに関連付けするAWSリソースのARNを指定します。AWSリソースの例) ALB,Cloudfront,API Gateway,AppSync |
スタックの作成を実行し、実行結果がCREATE_COMPLETE
になっていることを確認します。
リソースの確認
テンプレートで定義したリソースが正常に作成・設定できているか確認します。
WAF
WAF & Shield コンソール で Web Acl
を選択します。
今回は東京リージョンで作成したので、リージョン選択欄にAsia Pacific (Tokyo)
を指定します。
作成されているWAFを選択します。
各タブを確認し、設定が適切であることを確認します。
Rules
Associated AWS resources
Logging and metrics
CloudWatchLogs
WAFのログ設定で設定されているLogGroupを選択します。
リソースベースポリシーのアクセス許可が正しく設定されていれば、ログストリームが出力されています。
設定は以上となりますが、今回ハマった箇所についてもお伝えします。
ハマりどころ
リソースベースポリシーの設定漏れ
AWS WAFのログをCloudWatchLogsに出力するためには、リソースベースポリシーが必要となります。
リソースベースポリシーとは、その名の通り操作対象のリソースに対して設定するポリシーです。
当初はこのポリシーを設定していなかったため、設定したCloudWatchLogsにログストリームが出力されませんでした。
そのため、リソースポリシーの設定を追加しました。
なおPolicyDocument
はStringで記述する必要があるため、書き方に注意してください。
WAFToCWLogsPolicy: Type: AWS::Logs::ResourcePolicy Properties: PolicyName: WAFToCWLogsPolicy PolicyDocument: Fn::Sub: - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "${CloudWatchLogsLogGroupArn}", "Condition": { "StringEquals": { "aws:SourceAccount": ${AWS::AccountId} }, "ArnLike": { "aws:SourceArn": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*" } } } ] } - CloudWatchLogsLogGroupArn: !GetAtt WAFLogGroup.Arn
なおCloudFormationでリソースベースポリシーが記述できるようになったのは、2021年7月ごろからのようです。
注意点として、CloudFormationで作成できるリソースベースポリシーはAWSアカウントの各リージョンにつき10個までという制限があります。
下記CloudFormationガイドより引用
AWS::Logs::ResourcePolicy - AWS CloudFormation
An account can have up to 10 resource policies per AWS Region.(アカウントには、AWS リージョンごとに最大 10 個のリソース ポリシーを含めることができます。)
そのため、リソースベースポリシーを量産する場合はResource
でワイルドカード(*)を利用したり、List形式で列挙するなど工夫が必要となります。
なお設定したリソースベースポリシーは下記のコマンドで確認できます。
aws logs describe-resource-policies --region ap-northeast-1
最後に
今回はAWS WAFのログをCloudWatchLogsに出力するCloudFormationで構築してみました。
手動で設定すると自動で作成されるリソースベースポリシーにハマりましたが、なんとか構築することができました。
同じようにハマってしまった方の参考になれば嬉しいです。
最後までお読みいただきありがとうございました!
以上、おつまみ(@AWS11077)でした!
参考
[アップデート] AWS WAFのログを直接CloudWatch LogsおよびS3に出力可能になりました | DevelopersIO